package com.ee.chat.common.service.impl;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ee.chat.common.dao.*;
import com.ee.chat.common.entity.*;
import com.ee.chat.common.serconfig.MyMapConfig;
import com.ee.chat.common.serconfig.MyNeteaseApp;
import com.ee.chat.common.service.IGeneralService;
import com.ee.chat.common.util.ConstantsUtil;
import com.ndhutu.ee.util.IPUtil;
import com.ndhutu.ee.util.StringUtil;
import com.ndhutu.ee.util.map.baidu.MapUtil;
import com.ndhutu.ee.util.netease.im.IMUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author Shane
 * @Date 2019/8/10 20:04
 */
@Service
public class GeneralServiceImpl implements IGeneralService {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Resource
    BaseMapper baseMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    ChannelMapper channelMapper;
    @Resource
    MyMapConfig mapConfig;
    @Resource(name = "stringRedisTemplate")
    StringRedisTemplate redisTemplate;
    @Resource
    MyNeteaseApp app;
    @Resource
    UserOperationLogMapper userOperationLogMapper;
    @Resource
    UserOnlineLogMapper userOnlineLogMapper;
    @Resource
    SysConfigMapper sysConfigMapper;
    @Resource
    ChannelUserLogMapper channelUserLogMapper;

    @Override
    public List<Map<String, Object>> getAreaLibToCity() {
        return getAreas(0, 2);
    }

    @Override
    public List<Map<String, Object>> getAreaLib() {
        return  getAreas(0);
    }

    private List<Map<String, Object>>  getAreas(Integer fatherAdCode){
        List<Map<String, Object>> citys = baseMapper.getAreaLib(fatherAdCode);
        if(citys.size() > 0){
            for(Map<String, Object> city : citys){
                Integer adCode = Integer.parseInt(city.get("adCode")+"");
                List<Map<String, Object>> childrens =  getAreas(adCode);
                city.put("childrens", childrens);
            }
            return citys;
        }else{
            return citys;
        }
    }

    private List<Map<String, Object>>  getAreas(Integer fatherAdCode, Integer level){
        if(level > 0){
            List<Map<String, Object>> citys = baseMapper.getAreaLib(fatherAdCode);
            if(citys.size() > 0){
                for(Map<String, Object> city : citys){
                    int l = new Integer(level);
                    Integer adCode = Integer.parseInt(city.get("adCode")+"");
                    l --;
                    List<Map<String, Object>> childrens =  getAreas(adCode, l);
                    city.put("childrens", childrens);
                }
                return citys;
            }else{
                return citys;
            }
        }
        return new ArrayList<>();
    }

    @Override
    public int getNewUserId() {
        int id = 0;
        boolean flag = true;
        while (flag){
            String firstNum = (int)(Math.random() * 9 + 1)+"";
            String otherNum = StringUtil.getRandomNumberStr(7);
            id = Integer.parseInt(firstNum+otherNum);
            User user = userMapper.selectById(id);
            if(user == null){
                break;
            }
        }
        return id;
    }

    @Override
    public String getNewInviteCode() {
        String inviteCode = "";
        boolean flag = true;
        while (flag){
            inviteCode = StringUtil.getInviteCode();
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("invite_code", inviteCode);
            User user = userMapper.selectOne(wrapper);
            if(user == null){
                break;
            }
        }
        return inviteCode;
    }

    @Override
    public String getNewChannelCode() {
        String code = "";
        boolean flag = true;
        while (flag){
            code = StringUtil.getRandomNumberStr(6);
            QueryWrapper<Channel> wrapper = new QueryWrapper<>();
            wrapper.eq("code", code);
           Channel channel = channelMapper.selectOne(wrapper);
            if(channel == null){
                break;
            }
        }
        return code;
    }

    /**
     * 获取位置信息
     * @Author Shane
     * @Date 2020/4/1 22:23
     * @param
     * @return
     */
    @Override
    public Map<String, String> getLocationInfo(HttpServletRequest request){
        Map<String, String> data = new HashMap();

        try {
            String ip = null, lnglat = null, city = null;
            String extra = request.getParameter("extra");
            if(!StrUtil.isEmptyIfStr(extra)){
                Map<String, Object> map = JSONObject.parseObject(extra, Map.class);

                //处理ip
                ip = map.get("ip") == null ? null : map.get("ip") + "";
                if(StrUtil.isEmptyIfStr(ip) || NetUtil.isInnerIP(ip)){
                    ip = IPUtil.getClientIP(request);
                }

                //处理经纬度
                lnglat = map.get("location") == null ? null : map.get("location") + "";
                if(StrUtil.isEmptyIfStr(lnglat) && !NetUtil.isInnerIP(ip)){
                    Map<String, Object> addr = MapUtil.getIpAddr(ip, mapConfig);
                    Map<String, Object> content = (Map)addr.get("content");
                    city = ((Map)content.get("address_detail")).get("city")+"";
                    lnglat = ((Map)content.get("point")).get("x") + "," + ((Map)content.get("point")).get("y");
                }

                //处理城市
                if(StrUtil.isEmptyIfStr(city) && !StrUtil.isEmptyIfStr(lnglat)){
                    Map<String, Object> addr  = MapUtil.geocoding(lnglat, mapConfig);
                    Map<String, Object> addressComponent = (Map) addr.get("addressComponent");
                    city = addressComponent.get("city") + "";
                }
            }

            data.put("ip", ip);
            data.put("lnglat", lnglat);
            data.put("city", city);

        } catch (Exception e){
            log.error("【获取用户位置错误】", e);
        }
        return data;
    }

    /**
     * 根据ip，匹配手机信息对应的邀请者信息
     * @Author Shane
     * @Date 2020/7/6 14:41
     * @param
     * @return
     */
    @Override
    public Map<String, String> handleInvite(HttpServletRequest request, String inviteCode, String channelCode) throws Exception {
        String ip = IPUtil.getClientIP(request);
//        String ip = "116.25.250.123";
        String extra = request.getParameter("extra");
        Map<String, String> extraMap = JSONObject.parseObject(extra, Map.class);

        boolean flag = false;
        String key = "data:ip:"+ip;
        Set<String> vals = redisTemplate.opsForSet().members(key);
        if(vals != null && vals.size() > 0){
            for(String val : vals){
                if(StringUtil.isEmpty(inviteCode) || "LUOXIANG".equals(inviteCode)){
                    Map<String, String> equipment = JSONObject.parseObject(val, Map.class);

                    if("android".equals((extraMap.get("sysType")+"")+"")){
                        if(!StringUtil.isEmpty(equipment.get("sysType")) && !StringUtil.isEmpty(equipment.get("sysVersion"))){
                            if(equipment.get("sysType").toLowerCase().equals(extraMap.get("sysType").toLowerCase()) && equipment.get("sysVersion").toLowerCase().equals(extraMap.get("sysVersion").toLowerCase())){
                                log.info("inviteCode更换成功：" + channelCode + "->" + equipment.get("inviteCode"));
                                inviteCode = equipment.get("inviteCode");
                                flag = true;
                            }
                        }

                        if(!StringUtil.isEmpty(equipment.get("phoneType")) && equipment.get("phoneType").toLowerCase().equals(extraMap.get("phoneType").toLowerCase())){
                            log.info("inviteCode更换成功：" + inviteCode + "->" + equipment.get("inviteCode"));
                            inviteCode = equipment.get("inviteCode");
                            flag = true;
                        }
                    }else{
                        if(!StringUtil.isEmpty(equipment.get("sysType")) && !StringUtil.isEmpty(equipment.get("sysVersion"))){
                            if(equipment.get("sysVersion").toLowerCase().equals(extraMap.get("sysVersion").toLowerCase())){
                                log.info("inviteCode更换成功：" + channelCode + "->" + equipment.get("inviteCode"));
                                inviteCode = equipment.get("inviteCode");
                                flag = true;
                            }
                        }
                    }
                }

                if(StringUtil.isEmpty(channelCode) || "LUOXIANG".equals(channelCode)){
                    Map<String, String> equipment = JSONObject.parseObject(val, Map.class);

                    if("android".equals((extraMap.get("sysType")+"").toLowerCase())){
                        if(!StringUtil.isEmpty(equipment.get("sysType")) && !StringUtil.isEmpty(equipment.get("sysVersion"))){
                            if(equipment.get("sysType").toLowerCase().equals(extraMap.get("sysType").toLowerCase()) && equipment.get("sysVersion").toLowerCase().equals(extraMap.get("sysVersion").toLowerCase())){
                                log.info("channelCode更换成功：" + channelCode + "->" + equipment.get("channelCode"));
                                channelCode = equipment.get("channelCode");
                                flag = true;
                            }
                        }

                        if(!StringUtil.isEmpty(equipment.get("phoneType")) && equipment.get("phoneType").toLowerCase().equals(extraMap.get("phoneType").toLowerCase())){
                            log.info("channelCode更换成功：" + channelCode + "->" + equipment.get("channelCode"));
                            channelCode = equipment.get("channelCode");
                            flag = true;
                        }
                    }else{
                        if(!StringUtil.isEmpty(equipment.get("sysType")) && !StringUtil.isEmpty(equipment.get("sysVersion"))){
                            if(equipment.get("sysVersion").toLowerCase().equals(extraMap.get("sysVersion").toLowerCase())){
                                log.info("channelCode更换成功：" + channelCode + "->" + equipment.get("channelCode"));
                                channelCode = equipment.get("channelCode");
                                flag = true;
                            }
                        }
                    }
                }

                if(flag){
                    redisTemplate.opsForSet().remove(key, val);
                }
            }
        }


        Map<String, String> data = new HashMap<>();
        data.put("inviteCode", inviteCode);
        data.put("channelCode", channelCode);
        return data;
    }

    /**
     * 处理绑定
     * @param userId        注册用户id
     * @param imei          注册设备编号
     * @param inviteCode    邀请码
     * @param channelCode   渠道邀请码
     * @param channelCode2  特殊渠道码
     * @throws Exception
     */
    @Override
    public void handleInviteBind(HttpServletRequest request, Integer userId, String imei, String inviteCode, String channelCode, String channelCode2) throws Exception {
        //一台设备只能有效注册一个账号
        if(imei != null){
            int num = userMapper.getImeiCount(imei);
            if(num <= 1){
                //弥补openinstall的不足，根据ip地址匹配信息
                Map<String, String> newCode = handleInvite(request, inviteCode, channelCode);
                inviteCode = newCode.get("inviteCode");
                channelCode = newCode.get("channelCode");
                if(!StringUtil.isEmpty(channelCode2)){
                    channelCode = channelCode2;
                }
                log.info("inviteCode:"+inviteCode+",channelCode:"+channelCode);

                //存在渠道
                boolean flag = true;
                if((!StringUtil.isEmpty(channelCode)) && flag){
                    QueryWrapper<Channel> wrapper1 = new QueryWrapper<>();
                    wrapper1.eq("`code`", channelCode);
                    Channel channel = channelMapper.selectOne(wrapper1);
                    if(channel != null && channel.getStatus() == 0){
                        ChannelUserLog channelUserLog = new ChannelUserLog(channel.getId(), userId);
                        channelUserLogMapper.insert(channelUserLog);

                        //处理邀请注册奖励
//                            if(channel.getType() == 1){
//                                yieldService.handleInviteRegYield(user.getId(), channel.getUserId(), 1);
//                            }
                        flag = false;
                    }
                }else if((!StringUtil.isEmpty(inviteCode)) && flag){
                    //存在邀请者
                    QueryWrapper<User> wrapper = new QueryWrapper<>();
                    wrapper.eq("invite_code", inviteCode);
                    User inviteUser = userMapper.selectOne(wrapper);
                    if(inviteUser != null){
                        //如果邀请者是渠道商，则任何邀请方式都归属在渠道商邀请方式下
                        Channel inviteChannel = channelMapper.selectByUserId(inviteUser.getId());
                        if(inviteChannel != null){
                            ChannelUserLog channelUserLog = new ChannelUserLog(inviteChannel.getId(), userId);
                            channelUserLogMapper.insert(channelUserLog);
                            log.info("用户邀请，已添加渠道邀请");
                            //处理邀请注册奖励
//                                if(inviteChannel.getType() == 1){
//                                    yieldService.handleInviteRegYield(user.getId(), inviteChannel.getUserId(), 1);
//                                }

                        }else{
                            userMapper.addUserInviteLog(userId, inviteUser.getId());
                            log.info("已添加用户邀请");
                            //处理邀请注册奖励
//                                yieldService.handleInviteRegYield(user.getId(), inviteUser.getId(), 0);
                        }
                    }
                }
            }else{
                log.info(userId+"用户注册添加邀请者失败，其当前设备IMEI："+imei+"号，已有注册");
            }
        }else{
            log.info("当前设备无法获取iemi值，不能添加邀请者");
        }
    }

    @Override
    public void sendFreeMsgInform(Integer userId) throws Exception {
        int from = Integer.parseInt(sysConfigMapper.getValue("customer_account"));
        Map<String, Object> body = new HashMap<>();
        body.put("msg", "普通用户，每天的前5条消息免费。亲，欢迎体验！");

        Map<String, Object> result = IMUtil.sendMsg(app.getIdPrefix()+from, app.getIdPrefix()+userId, 10, body, app);
        String msgid = result.get("msgid")+"";
        if(!StringUtil.isEmpty(msgid)){
            String k = ConstantsUtil.USER_IM + "" + msgid;
            redisTemplate.opsForHash().put(k, "is_sys", "1");

            //设置1分钟超时，防止没有接收回调长期存储
            redisTemplate.expire(k, 1, TimeUnit.MINUTES);
        }
    }

    @Override
    public int versionCompare(String token, String androidAppVersion, String iosAppVersion) throws Exception {
        String key = ConstantsUtil.USER_TOKEN + token;
        Object extraObj = redisTemplate.opsForHash().get(key, "extra");
        if(!StringUtil.isEmpty(extraObj)){
            Map<String, Object> extra = JSONObject.parseObject(extraObj+"", Map.class);

            //android比较
            if(!StringUtil.isEmpty(androidAppVersion) && "android".equals(extra.get("sysType")) && !StringUtil.isEmpty(extra.get("appVersion"))){
                return StringUtil.compareVersion(extra.get("appVersion")+"", androidAppVersion);
            }

            //ios比较
            if(!StringUtil.isEmpty(iosAppVersion) && "iOS".equals(extra.get("sysType")) && !StringUtil.isEmpty(extra.get("appVersion"))){
                return StringUtil.compareVersion(extra.get("appVersion")+"", iosAppVersion);
            }
        }

        return 0;
    }

    /**
     * 添加用户操作状态
     * @param userOperationLog
     * @throws Exception
     */
    @Override
    public void addUserOperationLog(UserOperationLog userOperationLog, HttpServletRequest request) throws Exception {
        if(userOperationLog.getOperationId() == 2){ //上线
            UserOperationLog temp = userOperationLogMapper.getNewsetOperationLog(userOperationLog.getUserId(), userOperationLog.getOperationId());
            if(temp == null){
                //第一次用户上线即为注册
                userOperationLog.setOperationId(1);
                userOperationLogMapper.insert(userOperationLog);
            }
        }

        //上线
        if(userOperationLog.getOperationId() == 1 || userOperationLog.getOperationId() == 2){
            addUserUpTime(userOperationLog.getUserId(), request);
        }

        //推送消息
        if(userOperationLog.getOperationId() == 3 || userOperationLog.getOperationId() == 4){
            Map<String, Object> message = userOperationLogMapper.getOperationMessgae(userOperationLog.getId());
            pushUserOperations(ConstantsUtil.USER_WS_OPERATION, message);
        }
    }

    /**
     * 添加上线时间
     * @param userId
     * @throws Exception
     */
    private void addUserUpTime(Integer userId, HttpServletRequest request) throws Exception {
        Date upTime = new Date();
        Map<String, String> location = getLocationInfo(request);
        UserOnlineLog userOnlineLog = new UserOnlineLog(userId, location.get("ip"), location.get("lnglat"), location.get("city"), upTime);
        userOnlineLogMapper.insert(userOnlineLog);
    }

    public void pushUserOperations(String channel, Map<String, Object> message){
        redisTemplate.convertAndSend(channel, JSONObject.toJSONString(message));
    }
}
